/* jshint esversion: 6 */
console.log('%c Pet %c 网页宠物\n %c作者: 小瑞猫',
    'font-family: "Helvetica Neue",Helvetica, Arial, sans-serif;font-size:64px;color:#FFB6C1;-webkit-text-fill-color:#FFB6C1;-webkit-text-stroke: 1px #FFB6C1;',
    'font-size:25px;color:#FFB6C1;', 'font-size:15px;color:#FFB6C1;');
/**
 * Pet 网页宠物
 */
function Pet($_) {
    var $ = {};
    if ($_) { $ = $_; }
    Reflect.setPrototypeOf($, Pet.prototype);
    //-> 创建 pet 底层框架
    var pet = PetUI('div').Child();
    pet.CSS('stroke-width:1;left:0px;top:0px;position:fixed;z-index:99999;width:' + $.ShowNodesSize.width + 'px;height:' + $.ShowNodesSize.height + "px");
    if ($.Expand.HasTouch()) {
        pet.CSS({
            top: $.Expand.Position.Win.Height - pet.offsetHeight + "px",
            left: ($.Expand.Position.Win.Width - pet.offsetWidth) / 2 + "px",
        });
    } else {
        //-> 开启移动
        pet.Element.MobileEvent().EnablementRemovable = true;
        //-> 移动位置
        pet.CSS({
            top: $.Expand.Position.Win.Height - pet.offsetHeight + "px",
            left: $.Expand.Position.Win.Width - pet.offsetWidth + "px",
        });
        //-> 限制移动
        pet.Element.GuaranteeCoords().EnablementUndo = true;
        pet.Element.GuaranteeCoords.Save();
    }
    //-> 对话框创建
    var Dialog = pet.$('div');
    Dialog.CSS($.TheDialogNodestyle);
    Dialog.style.left = '0px';
    Dialog.style.top = '0px';
    Dialog.style.display = 'none';
    Dialog.style.background = 'url(' + $.TheDialogNodeSrc + ') left top repeat';
    Dialog.CSS({
        width: $.TheDialogNodestyleSize.width + "px",
        height: $.TheDialogNodestyleSize.height + "px"
    });
    //-> 显示处理
    var ShowDiv = pet.$("div");
    // 显示默认
    var Scene = ShowDiv.$("canvas");
    var Palette = Scene.getContext("2d");
    Scene.width = $.ShowNodesSize.width;
    Scene.height = $.ShowNodesSize.height;
    Scene.style.float = 'left';
    // 设置显示
    if ($.ShowNodesSrc) {
        let image = new Image();
        image.src = $.ShowNodesSrc;
        image.onload = function () {
            Palette.drawImage(image, 0, 0, $.ShowNodesSize.width, $.ShowNodesSize.height);
        };
    }
    // 禁止 拖动 左键 事件
    Scene.onmousedown = function (e) {
        e.preventDefault();
    };
    //----------------------------------------------------------------
    // 事件列表
    var MenuTheLock = false, Mouse;
    //-> 对话框坐标处理
    if ($.Expand.IsPC()) {
        Mouse = () => {
            var S = parseInt(pet.style.left) + parseInt(pet.clientWidth);
            Dialog.style.top = parseInt(Dialog.clientTop) + $.DialogSkewing.top + 'px';
            if ($.Expand.Position.Win.Width / 2 > S) {
                // 右边显示
                Dialog.style.left = parseInt(pet.clientWidth) + $.DialogSkewing.width + 'px';
            } else {
                // 左边显示
                Dialog.style.left = -parseInt(Dialog.clientWidth) - 10 + $.DialogSkewing.left + 'px';
            }
        };
        pet.Element.MobileEvent.TheMouseCallback = (e) => {
            if (pet.Element.MobileEvent.MouseDown) {
                Lock = true;
            }
            Mouse();
        };
    } else {
        Mouse = () => {
            Dialog.style.top = $.DialogSkewing.top + "px";
            Dialog.style.left = $.DialogSkewing.left + "px";
            Dialog.style.width = $.Expand.Position.Win.Width - $.DialogSkewing.width + "px";
            Dialog.style.height = $.Expand.Position.Win.Height - $.DialogSkewing.height + "px";
            Dialog.style.position = 'fixed';
        };
    }
    // 菜单列表
    var MenuList = [], MenuI = 0;
    var Menu = () => {
        if (MenuTheLock) {
            return false;
        }
        if (MenuList.length > 0) {
            Dialog.Element.Display(true);
            MenuTheLock = true;
            // 翻页按钮
            let div_next = document.createElement("button");
            Dialog.appendChild(div_next);
            div_next.style = 'left: 10px;bottom: 15px;position: absolute;';
            div_next.innerText = "上一页";
            div_next.AddHandler = PetUI.Additional.AddHandler;
            let div_page = document.createElement("button");
            Dialog.appendChild(div_page);
            div_page.style = 'bottom: 15px;position: absolute;right: 15px;';
            div_page.innerText = "下一页";
            div_page.AddHandler = PetUI.Additional.AddHandler;
            // 菜单 div
            var div = document.createElement("div");
            div.style = 'width: 100%;height: calc(100% - 40px);';
            div.$ = PetUI;
            Dialog.appendChild(div);
            // 防止超下标
            MenuI = 0;
            div.appendChild(MenuList[MenuI]);
            // 注册事件
            div_next.AddHandler("click", (e) => {
                if (MenuI > 0) {
                    div.removeChild(MenuList[MenuI]);
                    MenuI--;
                    div.appendChild(MenuList[MenuI]);
                }
            });
            div_page.AddHandler("click", (e) => {
                if (MenuList.length - 1 > MenuI) {
                    div.removeChild(MenuList[MenuI]);
                    MenuI++;
                    div.appendChild(MenuList[MenuI]);
                }
            });
            // 弹出菜单
            if ($.Expand.IsPC()) {
                $.DialogSkewing.top = -200;
                Dialog.CSS({
                    width: $.TheDialogNodestyleSize.Menu.width + "px",
                    height: $.TheDialogNodestyleSize.Menu.height + "px"
                });
                Mouse();
                // 隐藏菜单
                setTimeout(() => {
                    $.DialogSkewing.top = 0;
                    Dialog.CSS({
                        width: $.TheDialogNodestyleSize.width + "px",
                        height: $.TheDialogNodestyleSize.height + "px"
                    });
                    Dialog.removeChild(div);
                    Dialog.removeChild(div_next);
                    Dialog.removeChild(div_page);
                    MenuTheLock = false;
                    Dialog.Element.Display(false);
                }, 20000);
            } else {
                // 隐藏菜单
                setTimeout(() => {
                    Dialog.removeChild(div);
                    Dialog.removeChild(div_next);
                    Dialog.removeChild(div_page);
                    MenuTheLock = false;
                    Dialog.Element.Display(false);
                }, 20000);
            }
        }
    };
    // 弹出对话框
    $.MessageBox = (call, time) => {
        if (call == undefined && time == undefined) {
            MenuTheLock = false;
            Dialog.Element.Display(false);
            return true;
        }
        if (MenuTheLock) {
            return false;
        }
        if (call) {
            MenuTheLock = true;
            Dialog.Element.Display(true);
            Mouse();
            let div = document.createElement("div");
            div.$ = PetUI;
            call(div);
            Dialog.appendChild(div);
            // 延时关闭
            if (time == undefined) { time = 5000; }
            setTimeout(() => {
                MenuTheLock = false;
                Dialog.Element.Display(false);
                Dialog.removeChild(div);
            }, time);
            return true;
        }
        return false;
    };
    // 单击事件
    var TheEventList = [];
    Scene.Element.Click = (e) => {
        var x = e.clientX - Scene.getBoundingClientRect().x;
        var y = e.clientY - Scene.getBoundingClientRect().y;
        // 判定事件
        for (var i = 0; i < TheEventList.length; i++) {
            if ($.Expand.IsPointInPolygon(x, y, TheEventList[i].Matrix)) {
                $.MessageBox((Dialog) => {
                    TheEventList[i].CallBack(Dialog, e);
                });
                return;
            }
        }
    };
    Scene.Element.Dblclick = (e) => {
        Menu();
    };
    // 设置事件
    Scene.Element.Set_Element();
    // 返回结构
    $.Div = pet;
    $.Scene = Scene;
    $.Palette = Palette;
    $.Dialog = Dialog;
    $.ShowDiv = ShowDiv;
    $.MenuList = MenuList;
    $.TheEventList = TheEventList;
    /**
     * 注册脚本
     */
    $.Script = () => new this.Script($);
    return $;
}
Pet.prototype = {
    // 精灵默认显示图片
    ShowNodesSrc: "", //./Data/Sprite.png
    // 精灵默认显示大小
    ShowNodesSize: {
        width: 200,
        height: 250
    },
    // 对话框默认显示图片
    TheDialogNodeSrc: "./Data/Dialog.png",
    // 对话框样式 (文本型,用于替换默认样式)
    TheDialogNodestyle: `
    position:absolute;
    font-size: 15px;
    overflow: auto;
    padding: 15px;
    border: 3px solid #FFE4E1;
    border-radius: 25px;
    background-position: left top;
    background-repeat: repeat;
    -moz-box-shadow: -3px -2px 7px #FAE3F4;
    -webkit-box-shadow: -3px -2px 7px #FAE3F4;
    box-shadow: -3px -2px 7px #FAE3F4`,
    // 对话框大小
    TheDialogNodestyleSize: {
        width: 200,
        height: 200,
        // 对话框菜单模式大小
        Menu: {
            width: 300,
            height: 400
        }
    },
    // 精灵信息/作者信息
    Message: {
        Name: "", // 精灵名称
        Gender: false, // 性别 true 男 false 女
        Update: [""], // 更新地址
        Author: [""], // 作者信息
        Contactway: [""], // 联系方式
        IntroduceMyself: [""], // 介绍信息
        HomePage: [""] // 主页/配布地址
    },
    // 坐标处理偏移
    DialogSkewing: {
        top: 0, // 顶边偏移
        left: 0, // 左边偏移
        width: 36, // 宽度偏移
        height: 36 // 高度偏移
    }
};
Pet.prototype.Expand = new PetExpand();
/**
 * 动态精灵
 */
Pet.prototype.Dynamic = function (width, height) {
    let $ = this;
    var Pai = {};
    Pai.Scene = document.createElement("canvas");
    Pai.Palette = Pai.Scene.getContext("2d");
    // 剪裁位置
    Pai.Tailor = {
        /*源图形*/
        dx: 0,      // 开始剪切的 x 坐标位置
        dy: 0,      // 开始剪切的 y 坐标位置
        dWidth: 0,  //  图像的宽度
        dHeight: 0, // 图像的高度
        /*目标画板*/
        x: 0,      // 绘制到左上角 X 坐标
        y: 0,      // 绘制到左上角 Y 坐标
        Width: 0,  // 源图像绘制到宽度
        Height: 0  // 源图像绘制到高度 
    };
    // 设置大小
    Pai.Scene.width = width;
    Pai.Scene.height = height;
    // 图片 -> 修改大小 -> 绘画[层]
    // 图片数组
    Pai.ImageArray = [];
    // 参数数组
    Pai.ParamArray = [];
    // 组数组
    Pai.GroupArray = {
        Default: [], // 默认组
    };
    // 加载完成
    Pai.onload = () => { };
    /**
     * 加载图片
     *      src     图片地址  
     *      Param   配置参数
     */
    var i = 0;
    Pai.LoadImg = function (src, Param) {
        var image = new Image();
        image.src = src;
        Param.imgid = Pai.ImageArray.push({ image: image, src: src }) - 1;
        let ret = Pai.SetParam(Param);
        // 初始化
        i++;
        image.onload = function () {
            i--;
            ret.Update();
            if (i < 1) { Pai.onload(); i = 0; }
        };
        return ret;
    };
    /**
     * 更新精灵显示
     */
    Pai.Painting = function () {
        let param = [];
        Pai.Scene.height = Pai.Scene.height;
        // 格式化层
        for (let n = 0; n < Pai.ParamArray.length; n++) {
            let i = Pai.ParamArray[n].Strata;
            if (Pai.ParamArray[n].show) {
                param.splice(i, 0, Pai.ParamArray[n]);
            }
        }
        // 绘画
        for (let n in param) {
            if (param.hasOwnProperty(n)) {
                let Param = param[n].Param;
                Pai.Palette.drawImage(
                    Pai.ImageArray[param[n].imgid].image,
                    Param.dx,
                    Param.dy,
                    Param.dWidth,
                    Param.dHeight,
                    Param.x,
                    Param.y,
                    Param.Width,
                    Param.Height
                );
            }
        }
        // 画到显示
        $.Scene.height = $.Scene.height;
        $.Palette.drawImage(
            Pai.Scene,
            Pai.Tailor.dx,
            Pai.Tailor.dy,
            width + Pai.Tailor.dWidth,
            height + Pai.Tailor.dHeight,
            Pai.Tailor.x,
            Pai.Tailor.y,
            $.Scene.width + Pai.Tailor.Width,
            $.Scene.height + Pai.Tailor.Height
        );
    };
    /** 
     * 添加Param参数
     * Param {
     *      id,       ID(唯一)
     *      imgid,    图片ID 
     *      src,      图片地址
     *      show,     是否显示
     *      mark,     标记
     *      group,    组设定
     *      Strata,   绘制层
     *      Param: {
     *           dx,      // 开始剪切的 x 坐标位置
     *           dy,      // 开始剪切的 y 坐标位置
     *           dWidth,  // 被剪切图像的宽度
     *           dHeight, // 被剪切图像的高度
     *           x,      // 源图像绘制到左上角 X 坐标
     *           y,      // 源图像绘制到左上角 Y 坐标
     *           Width,  // 源图像绘制到宽度
     *           Height  // 源图像绘制到高度 
     *      }
     * }
     **/
    Pai.SetParam = function (Param) {
        var ret = {
            id: Pai.ParamArray.length,
            show: Param.show == undefined ? true : false, // 是否显示
            group: Param.group == undefined ? "Default" : Param.group,   // 组设定
            Strata: Param.Strata == undefined ? Pai.ParamArray.length : Param.Strata,
            Param: {
                dx: Param.dx == undefined ? 0 : Param.dx,
                dy: Param.dy == undefined ? 0 : Param.dy,
                x: Param.x == undefined ? 0 : Param.x,
                y: Param.y == undefined ? 0 : Param.y,
            }
        };
        // 设置组
        if (Pai.GroupArray[ret.group] == undefined) {
            Pai.GroupArray[ret.group] = [];
        } else if (ret.group != "Default") {
            ret.show = false;
        }
        ret.mark = Param.mark == undefined ? Pai.GroupArray[ret.group].length : Param.mark;
        Pai.GroupArray[ret.group].push(ret.id);
        ret.imgid = Param.imgid;
        ret.Update = function () {
            let image = Pai.ImageArray[Param.imgid].image;
            ret.Param.dWidth = Param.dWidth == undefined ? image.width : Param.dWidth;
            ret.Param.dHeight = Param.dHeight == undefined ? image.height : Param.dHeight;
            ret.Param.Width = Param.Width == undefined ? image.width : Param.Width;
            ret.Param.Height = Param.Height == undefined ? image.height : Param.Height;
        };
        ret.Update();
        Pai.ParamArray.push(ret);
        return ret;
    };
    /**
     * 设置绘画显示
     *      group 组
     *      mark  标识
     *      hide  隐藏显示(可空)
     */
    Pai.SetPainting = function (group, mark, hide) {
        let Group = Pai.GroupArray[group];
        if (Group && mark != undefined) {
            for (let n = 0; n < Group.length; n++) {
                if (Pai.ParamArray[Group[n]].mark == mark) {
                    if (hide) {
                        Pai.ParamArray[Group[n]].show = false;
                    } else {
                        Pai.ParamArray[Group[n]].show = true;
                    }
                } else {
                    Pai.ParamArray[Group[n]].show = false;
                }
            }
            return true;
        }
        return false;
    };
    /**
     * 导出图片
     */
    Pai.GetCanvasImg = function (onload) {
        //新Image对象，可以理解为DOM  
        var image = new Image();
        // Pai.Scene.toDataURL 返回的是一串Base64编码的URL
        // 指定格式 PNG  
        image.src = Pai.Scene.toDataURL("image/png");
        image.onload = onload;
        return image;
    };
    /**
     * 导出配置
     *    image 导出图片到配置
     */
    Pai.GetDeploy = function (image) {
        let Image = [];
        for (var i = 0; i < Pai.ImageArray.length; i++) {
            if (image) {
                let canvas = document.createElement("canvas");
                let ctx = canvas.getContext("2d");
                let img = Pai.ImageArray[i].image;
                canvas.width = img.width;
                canvas.height = img.height;
                ctx.drawImage(img, 0, 0, img.width, img.height);
                let ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
                let dataURL = canvas.toDataURL("image/" + ext);
                Image.push(dataURL);
            } else {
                Image.push(Pai.ImageArray[i].src);
            }
        }
        return JSON.stringify({
            width: width,
            height: height,
            Tailor: Pai.Tailor,
            Image: Image,
            Group: Pai.GroupArray,
            Param: Pai.ParamArray
        });
    };
    /**
     * 设置配置
     */
    Pai.SetDeploy = function (json) {
        let obj = {};
        if (typeof json == "string") {
            obj = JSON.parse(json);
        } else {
            obj = json;
        }
        // 设置大小
        Pai.Scene.width = obj.width;
        Pai.Scene.height = obj.height;
        // 剪裁位置
        Pai.Tailor = obj.Tailor;
        // 设置参数
        Pai.GroupArray = obj.Group;
        Pai.ParamArray = obj.Param;
        let img = obj.Image, n = 0;
        for (let i = 0; i < img.length; i++) {
            let image = new Image();
            image.src = img[i];
            n++;
            Pai.ImageArray.push({
                src: img[i],
                image: image
            });
            image.onload = function () {
                n--;
                if (n < 1) {
                    Pai.onload();
                    n = 0;
                }
            };
        }
    };
    /**
     * 加载配置
     */
    Pai.LoadDeploy = function (url) {
        $.Expand.HTTP.Get({
            url: url,
            responseType: 'text'
        }, (e, data) => {
            if (e == null) {
                Pai.SetDeploy(data);
            } else {
                console.warn(e);
            }
        });
    };
    /**
     * 修改表情
     *
    $.Script.ModifyFace = {
        Start: "$",
        Finish: ";",
        Feature: (text) => {
            if (text[0][0] == "/") {
                let mark = text[0].slice(1, text[0].length);
                mark = mark.replace(/(\s+|\n)/g, "").split(',');
                if (mark[2] == undefined || mark[2] == "false" || mark[2] == false) {
                    mark[2] = false;
                } else {
                    mark[2] = true;
                }
                let jieg = Pai.SetPainting(...mark);
                Pai.Painting();
                return jieg;
            } else {
                for (let i = 0; i < Pai.ParamArray.length; i++) {
                    if (Pai.ParamArray[i].mark == text[0]) {
                        let jieg = Pai.SetPainting(Pai.ParamArray[i].group, text[0]);
                        Pai.Painting();
                        return jieg;
                    }
                }
            }
            return false;
        }
    };
    */
    return Pai;
};
/**
 *  精灵对话语法定义
 *  标记符
 *      ... 合并数组
 *      !   逻辑取反
 *  运算符
 *      +,-,*,/
 *  判读符
 *      ==,>,<,>=,<=
 */
Pet.prototype.Script = function (pet) {
    // 检查依赖
    if (PetScript == undefined) { return null; }
    var $ = new PetScript();
    Reflect.setPrototypeOf(this, $);
    Reflect.setPrototypeOf($.VariableChain, pet.Message);
    // 加载库
    // 初始化
    this.InitDefault();
    // 标记符
    this.SetStart("...", function (param, i) {
        // 删除当前
        param.splice(i, 1);
        if (typeof param[i] == "object") {
            param.splice(i + 1, 0, ...(param[i].Chain));
        }
        param.splice(i, 1);
    }).WhetherHandler = true;
    this.SetStart("!", function (param, i) {
        param.splice(i, 1);
        param.splice(i, 1, !param[i]);
    }).WhetherHandler = true;
    // 判断符
    var manage = function (course, N) {
        course[N].Chain = [course[N - 1], course[N + 1]];
    };
    this.SetOperator("==", manage, (param) => parseInt(param[0]) == parseInt(param[1]));
    this.SetOperator(">", manage, (param) => parseInt(param[0]) > parseInt(param[1]));
    this.SetOperator("<", manage, (param) => parseInt(param[0]) < parseInt(param[1]));
    this.SetOperator(">=", manage, (param) => parseInt(param[0]) >= parseInt(param[1]));
    this.SetOperator("<=", manage, (param) => parseInt(param[0]) <= parseInt(param[1]));
    // 精灵脚本 API 定义
    /**
     * 绑定事件
     *      添加坐标: @ID;[坐标数组];
     *      添加对话: @ID;{对话脚本};
     *      参数设置: @ID;(层参数);
     * 注:
     *      分号可省略
     */
    var ElvEvents = {};
    this.ElvEvents = ElvEvents;
    this.SetStart("@", function (param, i) {
        // 删除标记符
        param.splice(i, 1);
        // 处理数据
        var ID = param[i], Param = param[i + 1];
        if (Param.Types == "Array") {
            ElvEvents[ID] = {
                Matrix: Param,
                Strata: 0,       // 层
                Random: [],     // 随机对话列表
                Restrict: "",  // 限制信息
                Specific: {}, // 特定对话列表
            };
            return;
        } else if (ElvEvents[ID] != undefined) {
            if (Param.Types == "Block" || Param.Types == "String") {
                ElvEvents[ID].Random.push(Param);
                return;
            } else if (Param.Types == "Scope") {
                ElvEvents[ID].Strata = parseInt(Param[0]);
                return;
            }
        }
        PetLog("解析错误: 绑定事件参数错误");
        PetLog("错误信息: ", param);
        PetLog("错误指针: ", i);
    }).WhetherHandler = true;
    /**
     * 获得变量
     *      ${变量名}
     */
    this.SetStart("$", function (param, i) {
        // 处理数据
        if ($.VariableChain[param[i]] != undefined) {
            param[i] = $.VariableChain[param[i]];
        } else if ($.VariableChain[param[i + 1]] != undefined) {
            param[i] = $.VariableChain[param[i + 1]];
            param.splice(i + 1, 1);
        } else {
            PetLog("赋值错误: 赋值对象未定义");
            PetLog("->解析数据:", param);
        }
    }).WhetherHandler = true;
    /**
     * 获得点击矩阵
     */
    var SaveTheCoordinates = false, CoordinateRrrays = [];
    $.GetClickMatrix = () => {
        CoordinateRrrays = [];
        SaveTheCoordinates = true;
        return () => {
            if (SaveTheCoordinates) {
                SaveTheCoordinates = false;
                CoordinateRrrays.push(CoordinateRrrays[0], CoordinateRrrays[1]);
                return "[" + CoordinateRrrays.join(",") + "]";
            }
            return "[]";
        };
    };
    /**
     * 脚本注册事件处理
     */
    pet.Scene.Element.Click = (e) => {
        let x = e.clientX - pet.Scene.getBoundingClientRect().x;
        let y = e.clientY - pet.Scene.getBoundingClientRect().y;
        if (SaveTheCoordinates) {
            CoordinateRrrays.push(x, y);
        }
        // 判定事件
        let n = -1;
        for (let id in ElvEvents) {
            if (ElvEvents.hasOwnProperty(id)) {
                if (pet.Expand.IsPointInPolygon(x, y, ElvEvents[id].Matrix)) {
                    if (n == -1) {
                        n = id;
                    } else if (ElvEvents[id].Strata > ElvEvents[n].Strata) {
                        n = id;
                    }
                }
            }
        }
        if (n != -1) {
            let l = ElvEvents[n].Random.length;
            l = parseInt(Math.random() * l, 10); // 取随机对话
            // 打开对话
            pet.MessageBox((Dialog) => {
                let Random = ElvEvents[n].Random[l];
                if (Random.Types == "String") {
                    Dialog.$("div").innerText = ElvEvents[n].Random[l];
                } else {
                    Dialog.$("div").innerText = $.Parse(ElvEvents[n].Random[l]).Chain.join("");
                }
            });
        }
    };
};